/**
 * Matrix.java
 */
package com.asa.hutils.teizheng.structure;

import java.io.Serializable;


/**
 * <p>计算的矩?/p>
 * @author Nano.Michael
 * @version 1.0.0
 * @date 2013-8-20
 * @author (latest modification by Nano.Michael)
 * @since 1.0.0
 */
public class Matrix implements Serializable{
	
	
	
	
	private static final long serialVersionUID = 1L;
	/**
	 * 列号	 */
	protected int cols = 0;
	/**
	 * 行号	 */
	protected int rows = 0;
	/**
	 * 娣囨繂鐡ㄩ惌鈺呮█閻ㄥ嫭鏆熼?	 */
	protected double[] d = null;
	/**
	 * 閺佺増宓?妤佹殶閿涘本娓堕崢鐔奉潗閻晠妯�惃鍕灙閺? */
	protected int dCols = 0;
	/**
	 * 行数
	 * 閻╃顕禍搴㈡付閸樼喎顫愰惌鈺呮█閿涘牏鏁遍弸鍕�閺傝纭跺妤�煂閿涘娈戠悰宀冨瘱閸ヨ揪绱濋張?鍨垫潻娆庨嚋鐎涙顔屾惔鏃囶嚉缁涘绨琑ange.all()閿涘苯缍媟owRange鐞氼偄锛愰弰搴礉閸掓瑨绻栨稉顏嗙叐闂冪數娈戠悰灞界磻婵? * 娑撳鐖ｉ惄绋款嚠娴滃孩娓堕崚婵堟畱閻晠妯�惃鍕攽娑撶皦owRange.begin()閿涘瞼鐓╅梼鐢垫畱鐞涘瞼绮ㄩ弶鐔剁瑓閺嶅洨娴夌�閫涚艾閺�鍨甸惃鍕叐闂冧絻顢戞稉绨塷wRange.end()閵嗗倷濡囨稉顏勫灙鐎涙劧绱�	 * 瑜�code>rowRange.start==2</code>娑�code>rowRange.end==5</code>閺冭绱濋柇锝勭疄鏉╂瑤閲滈惌鈺呮█閻╃顕禍搴㈡付閸樼喎顫愰惌鈺呮█閻ㄥ嫯顢戦惃鍕磻婵? * 閸滃瞼绮ㄩ弶鐔剁瑓閺嶅洣璐�閸�閵嗗倽绻栨稉顏勭摟濞堝吀绔撮懜顒傛暠閿�	 * @see #at(Range, Range)
	 * @see #set(Range, Range, Matrix)
	 * 娴ｈ法鏁? */
	protected Range rowRange = null;
	/**
	 * 列数
	 * 閻╃顕禍搴㈡付閸樼喎顫愰惌鈺呮█閻ㄥ嫬鍨懠鍐ㄦ纯閿涘矁袙闁插﹤鎮�	 * @see #rowRange
	 */
	protected Range colRange = null;
	
	private Matrix(){ }
	
	/**
	 * 初始化矩阵，两个参数，矩阵的行数、矩阵的列数
	 * 娴ｈ法鏁ゆ竟鐗堟閻ㄥ嫯顢戦弫鐨塷ws閸滃苯鍨弫鐧眔ls閺嬪?娑�閲滈惌鈺呮█閿涘本顒濋弮璺哄敶鐎涙ê鍑＄紒蹇氼潶閸掑棝鍘�	 * @param rows 閻晠妯�悰灞炬殶閵? * @param cols 閻晠妯�崚妤佹?	 */
	public Matrix(int rows, int cols){
		this(rows, cols, new double[cols * rows]);
	}
	
	/**
	 * 初始化矩阵data输入的就是矩阵值，没错，你看到的这个数据是一维的
	 * 娴ｈ法鏁ゆ竟鐗堟閻ㄥ嫯顢戦弫鏉挎嫲閸掓鏆熸禒銉ュ挤妫板嫬鍘涢崚鍡涘帳閻ㄥ嫬寮荤划鎯у濞搭喚鍋ｉ崹瀣殶閹诡喗鐎柅鐘辩娑擃亞鐓╅梼鐐�
	 * <br><b><i>NOTICE:</i></b> 婵?倹鐏夐惌鈺呮█閻ㄥ嫬銇囩亸蹇ョ礄缁涘绨悰灞炬?閸掓鏆熼敍澶婄毈娴滃酣顣╅崗鍫濈摠閸屻劎娈戦弫鐗堝祦閻ㄥ嫰鏆辨惔锔肩礉缁嬪绨懗钘夘檮濮濓絽鐖堕惃鍕箥鐞涘矉绱濇担鍡樻Ц楠炴湹绗? * 閹恒劏宕樻潻娆愮壉閸嬫哎?
	 * @see #Matrix(int, int)
	 * @param rows 閻晠妯�悰灞炬殶閵? * @param cols 閻晠妯�崚妤佹殶閵? * @param data 妫板嫬鍘涚�妯哄亶閻ㄥ嫭鏆熼幑顔?	 */
	public Matrix(int rows, int cols, double[] data){
		if (cols <= 0 || rows <= 0)
			throw new IllegalArgumentException("Matrix, columns and rows must be positive integer.");
		if (cols * rows > data.length)
			throw new IllegalArgumentException("Matrix, the size of the matrix does not match the length of the data.");
		this.cols = cols;
		this.rows = rows;
		this.d = data;
		this.dCols = cols;
		rowRange = new Range(0, rows);
		colRange = new Range(0, cols);
	}
	
	/**
	 * 是否是一个向量
	 * 閸掋倖鏌囨稉?閲滈惌鈺呮█閺勵垰鎯佹稉鍝勬倻闁插骏绱欓崚妤�?闁插繑鍨ㄧ悰灞芥倻闁插骏绱�	 * @return
	 */
	public boolean isVector(){
		return (rows!= 1&&cols!=1);
	}
	
	/**
	 * 是否是行向量
	 * 閸掋倖鏌囬惌鈺呮█閺勵垰鎯佹稉楦款攽閸氭垿鍣? * @return
	 */
	public boolean isRowVector(){
		return rows==1;
	}
	
	/**
	 * 是否是列向量
	 * 閸掋倖鏌囬惌鈺呮█閺勵垰鎯佹稉鍝勫灙閸氭垿鍣? * @return
	 */
	public boolean isColumnVector(){
		return cols==1;
	}
	
	/**
	 * 判断两个矩阵的行数和列数是否是一致的
	 * 閸掋倖鏌囨稉銈勯嚋閻晠妯�弰顖氭儊閺勵垰鎮撻崹瀣叐闂冪绱欓崡??閸掓娴夌粵澶涚?	 * @param x
	 * @return 閸氬苯鐎锋潻鏂挎?code>true</code>閿涘苯寮芥稊瀣灟閸? */
	public boolean sameType(Matrix x){
		return (rows==x.rows&&cols==x.cols);
	}
	
	/**
	 * 是否是nXn的矩阵
	 * 閸掋倖鏌囬弰顖氭儊娑撶儤鏌熼梼鐐?	 * @return
	 */
	public boolean isSquare(){
		return rows==cols;
	}
	
	/**
	 * 矩阵的大小
	 * 瀵版鍩岄惌鈺呮█婢堆冪毈閿涘澃ize=rows*columns閿�	 * @return
	 */
	public int size(){
		return rows*cols;
	}
	
	/**
	 * 绝对值
	 * 鐠侊紕鐣婚惌鈺呮█閻ㄥ嫮绮风�鐟?	 * @param reserve 閹稿洨銇氶弰顖氭儊娣囨繄鏆�崢鐔奉潗閻晠妯�敍??code>reserve==false</code>閿涘本鏌熷▔鏇炵殺娴ｈ法鏁ょ紒婵嗩嚠閸婅偐鐓╅梼鍨禌閹广垹甯慨?叐闂冪?
	 * @return 閻晠妯�惃鍕卜鐎电懓?閻晠妯? * @see #abs()
	 */
	public Matrix abs(boolean reserve){
		Matrix x = reserve?new Matrix(rows,cols):this;
		for (int i=0; i<rows; i++)
			for (int j=0; j<cols; j++){
				double d = at(i, j);
				x.set(i, j, d>=0.?d:-d);
			}
		return x;
	}
	
	/**
	 * 矩阵绝对值化
	 * 鐠侊紕鐣婚惌鈺呮█閻ㄥ嫮绮风�鐟�閵? * <br><br><b><i>NOTICE:</i></b>閺傝纭剁亸鍡樻禌閹广垹甯慨?叐闂冪?
	 * @return 閻晠妯�惃鍕卜鐎电懓?閻晠妯�妴?	 * @see #abs(boolean)
	 */
	public Matrix abs(){
		return abs(false);
	}
	
	/**
	 * 矩阵清零，就是所有值都是0
	 * 鐏忓棛鐓╅梼鍨闂嗚翰?
	 */
	public void clear(){
		for (int i = 0; i < rows; i++)
			for (int j = 0; j < cols; j++)
				set(i, j, 0);
	}
	
	/**
	 * 矩阵复制
	 * 鐏忓棛鐓╅梼鍨鐠愭繂鍩岄崣锕�樆娑�閲滈惌鈺呮█閿涘本顒濋弮璁圭礉鏉╂瑤琚辨稉顏嗙叐闂冮潧绻�い缁樻Ц閸氬苯鐎烽惃鍕剁礉閺佺増宓佺亸鍡楃暚閸忋劍?圭拹婵嗗煂閺傛壆娈戦惌鈺呮█閿涘奔绲鹃弰顖涙?ㄥ嫮鐓╅梼闈涚殺閸滃苯缍嬮崜宥囨畱閻晠妯�	 * 閺勵垰鐣崗銊у缁斿娈戦妴?	 * @param x 閻╊喗鐖ｉ惌鈺呮█閵? */
	public void copyTo(Matrix x){
		if (x.rows != rows || x.cols != cols)
			throw new IllegalArgumentException("Matrix copy, size not match.");
		for (int i = 0; i < rows; i++)
			for (int j = 0; j < cols; j++)
				x.set(i, j, at(i, j));
	}
	
	/**
	 * 将矩阵变成一维数组
	 * 鐏忓棛鐓╅梼浣冩祮閹诡澀璐�缂佸瓨鏆熺紒鍕剁礉濮濄?妞傞弬瑙勭?娴犮儴顢戞禒搴?箯閼峰啿褰搁敍灞间簰閸掓ぞ绮犳稉濠呭殾娑撳銆庢惔蹇撶殺閻晠妯�潪顒佸床娑�缂佸瓨鏆熺紒鍕?	 * <br><b><i>NOTICE:</i></b>瀵版鍩岄惃鍕殺閺勵垳鐓╅梼鍏歌厬閺佹壆绮嶉惃鍕鐠愭繐绱濇俊鍌涚亯娑撳秵鍏傞崘宥呭綗婢舵牕绱戞潏鐔风摠閸屻劎鈹栭梻杈剧礉鐠囪渹濞囬悽鈻凘link #data()}閺傝纭堕敍?	 * 娴ｅ棙妲稿銈嗘煙濞夋洝绻戦崶鐐电叐闂冮潧鍙忛柈銊ュ帗缁辩媴绱濇稉宥堝厴瀵版鍩?鎰叐闂冪绱欓悽杈ㄦ煙濞夋洩绱皗@link #at(Range, Range)}閿涘瘚@link #col(int)}閿涘瘚@link #row(int)}
	 * 瀵版鍩岄敍澶屾畱閸忓啰??	 * @return
	 */
	public double[] toArray(){
		double[] x = new double[size()];
		int c = 0;
		for (int i=0; i<rows; i++){
			for (int j=0; j<cols; j++){
				x[c] = at(i, j);
				c++;
			}
		}
		return x;
	}
	
	/**
	 * 将一维数组变成矩阵
	 * 鐏忓棛鐓╅梼浣冩祮閹诡澀璐�缂佸瓨鏆熺紒鍕�
	 * <br><b><i>NOTICE:</i></b> 瀵版鍩岄惃鍕殺閺勵垳鐓╅梼鍏歌厬閺佹壆绮嶉惃鍕鐠愭縿?
	 * @return
	 */
	public double[][] to2DArray(){
		double[][] x = new double[rows][cols];
		for (int i=0; i<rows; i++)
			for (int j=0; j<cols; j++)
				x[i][j] = at(i,j);
		return x;
	}
	
	/**
	 * 获取矩阵值
	 * 閼惧嘲褰囩�妯哄亶娴滃海鐓╅梼鍏歌厬閻ㄥ嫭鏆熼幑顔�
	 * @return 閺佺増宓? */
	public double[] data(){
		return this.d;
	}
	
	/**
	 * 总行数
	 * 閼惧嘲褰囬惌鈺呮█閻ㄥ嫬鍨弫鑸?	 * @return 閻晠妯�惃鍕灙閺佽埇?
	 */
	public int columns(){
		return this.cols;
	}
	
	/**
	 * 总列数
	 * 閼惧嘲褰囬惌鈺呮█閻ㄥ嫯顢戦弫鑸?	 * @return 閻晠妯�悰灞炬殶閵? */
	public int rows(){
		return this.rows;
	}
	
	/**
	 * 提取某一列
	 * 閼惧嘲褰囬惌鈺呮█閸︺劏顢戞稉?垼娑撶婢跺嫮娈戠悰灞芥?闁插?
	 * @param i 鐞涘奔绗呴弽鍥�
	 * @return 閻楃懓鐣鹃惃鍕攽閸氭垿鍣洪?	 */
	public Matrix row(int i){
		return at(new Range(i, i+1), Range.all());
	}
	
	/**
	 * 提取某一行
	 * 閼惧嘲褰囬惌鈺呮█閸︺劌鍨稉?垼娑撶婢跺嫮娈戦崚妤�?闁插?
	 * @param i 閸掓ぞ绗呴弽鍥�
	 * @return 閻楃懓鐣鹃惃鍕灙閸氭垿鍣洪?	 */
	public Matrix col(int i){
		return at(Range.all(), new Range(i, i+1));
	}
	
	/**
	 * 矩阵增量
	 * 閺嬪?娑�閲滄禒搴濅簰pitch娑撴椽妫块梾鏂剧矤begin閸掔櫝nd闁帒顤冮惃鍕倻闁插繈?
	 * @param begin 閸氭垿鍣哄?顫愰弫鐗堝祦
	 * @param pitch 闂傛挳娈? * @param end 閸氭垿鍣虹紒鎾存?	 * @return
	 */
	public static Matrix increment(double begin, double pitch, double end){
		int r = (int)((end-begin)/pitch);
		if (r<=0)
			throw new IllegalArgumentException("Matrix increment, end must greater than begin.");
		Matrix x = new Matrix(r, 1);
		double pre = begin;
		for (int i=0; i<x.rows; i++){
			x.set(i, pre);
			pre += pitch;
		}
		return x;
	}
	
	/**
	 * 閺嬪?娑�閲滈惌鈺呮█瑜般垹顩�A=u*I, I 閺勵垰宕熸担宥呮倻闁?u 閺勵垯绔存稉顏呯垼闁插繈?
	 * @param size 閻晠妯�惃鍕珶闂�￥? (size=rows=columns)
	 * @param scale 缂傗晜鏂佸В鏂垮灙閵�	 * @return A 
	 * @see #unit(int)
	 */
	public static Matrix unit(int size, double scale){
		Matrix x = new Matrix(size, size);
		for (int i = 0; i < size; i++)
			x.set(i, i, scale);
		return x;
	}
	
	/**
	 * 閺嬪?娑�閲滈崡鏇氱秴閻晠妯�妴?	 * @param size 閻晠妯�潏褰掓毐閵�size=rows=columns)
	 * @return 閸楁洑缍呴惌鈺呮█閵? * @see #unit(int, double)
	 */
	public static Matrix unit(int size){
		return unit(size, 1.);
	}
	
	/**
	 * 閺嬪?娑�閲滈??崗鍐閸忛攱婀?绋挎倱閺佺増宓侀惃鍕叐闂冪绱濊ぐ銏狀洤閿涙=N*scale閿涘娑�閻晠妯�敍?籧ale娑撹櫣缂夐弨鐐槷娓氬?
	 * @param rows 閻晠妯�悰灞炬殶閵? * @param cols 閻晠妯�崚妤佹殶閵? * @param scale 缂傗晜鏂佸В鏂剧伐閵�	 * @return A 
	 * @see #ones(int, int)
	 */
	public static Matrix ones(int rows, int cols, double scale){
		Matrix x = new Matrix(rows, cols);
		for (int i = 0; i < x.rows; i++)
			for (int j = 0; j < x.cols; j++)
				x.set(i, j, scale);
		return x;
	}
	
	/**
	 * 閺嬪?娑�閲滈??崗鍐娑�閻ㄥ嫮鐓╅梼鐐�
	 * @param rows 閻晠妯�悰灞炬殶閵? * @param cols 閻晠妯�崚妤佹殶閵? * @return A
	 * @see #ones(int, int, double)
	 */
	public static Matrix ones(int rows, int cols){
		return ones(rows, cols, 1.);
	}
	
	/**
	 * 鐠侊紕鐣婚惌鈺呮█閻ㄥ嫯鎶楅?	 * @return 閻晠妯�惃鍕姉閵? */
	public double trace(){
		if (rows != cols)
			throw new UnsupportedOperationException("Matrix trace, only squre matrix has trace.");
		double tr = 0.;
		for (int i = 0; i < rows; i++)
			tr += at(i, i);
		return tr;
	}
	
	/**
	 * 閼惧嘲褰囬惌鈺呮█閸︺劋绗呴弽鍣勬径鍕畱閸婄?绱欑悰灞芥?闁插繑鍨ㄩ崚妤�倻闁插繐娼庨崣顖ょ礆閵�	 * @param i 娑撳鐖ｉ妴?	 * @return 閸婄?
	 * @see #at(int, int)
	 * @see #at(Range, Range)
	 */
	public double at(int i){
		if (rows != 1 && cols != 1)
			throw new UnsupportedOperationException("Matrix at, only vector takes one parameter.");
		if (rows == 1)
			return at(0, i);
		else
			return at(i, 0);
	}
	
	/**
	 * 閼惧嘲褰囬惌鈺呮█閸︺劏顢戞稉?垼娑撶閸掓ぞ绗呴弽鍥﹁礋j婢跺嫮娈戦崐绗�
	 * @param i 鐞涘奔绗呴弽鍥�
	 * @param j 閸掓ぞ绗呴弽鍥�
	 * @return 閸婄?
	 */
	public double at(int i, int j){
		if (i < 0 || i >= rows || j < 0 || j >= cols)
			throw new IndexOutOfBoundsException("Matrix at, index out of range.");
		return d[(i + rowRange.begin()) * dCols + j + colRange.begin()];
	}
	
	/**
	 * 閼惧嘲褰囬悽杈攽閼煎啫娲块崪灞藉灙閼煎啫娲块崘鍐茬暰閻ㄥ嫬鐡欓惌鈺呮█閵�	 * <br><b><i>NOTICE:</i></b> 閻㈣精绻栫粔宥嗘煙?繗骞忛崣鏍畱鐎涙劗鐓╅梼闈涚殺娑撳秳绱扮悮顐ｅ鐠愭繐绱濇俊鍌涚亯娴ｇ姵鍏傞懢宄扮繁閻晠妯�惃鍕摍閻晠妯�敍灞借嫙娑撴棃娓剁憰浣锋叏閺�懓鍙炬稉顓犳畱閸婄》绱濇担鍡樻Ц
	 * 閸欏牅绗夌敮灞炬箿閸樼喎顫愰惌鈺呮█娑擃厾娈戦崐鑹邦潶閺�懓褰夐敍灞肩稑鎼存棁顕氱紓鏍у晸閸嶅繐顩ф稉?╁敩閻緤绱? * <code><br>Matrix y=new Matrix(2,2); //create a new matrix with 2 rows and 2 columns
	 * <br>x.at(new Range(1,3), new Range(2,4).copyTo(y); //copy the sub-matrix of x to y</code>
	 * @param row  Row range
	 * @param col Column range
	 * @return A sub-matrix of the matrix
	 * 
	 * @see #copyTo(Matrix)
	 */
	public Matrix at(Range row, Range col){
		row = row.equals(Range.all()) ? this.rowRange:
			new Range(row.begin() + this.rowRange.begin(), row.end() + this.rowRange.begin());
		col = col.equals(Range.all()) ? this.colRange: 
			new Range(col.begin() + this.colRange.begin(), col.end() + this.colRange.begin());
		
		if (!this.rowRange.isContain(row) || !this.colRange.isContain(col))
			throw new IllegalArgumentException("Matrix at, out of range.");
		Matrix x = new Matrix();
		// row range of x
		x.rowRange = row;
		//column range of x
		x.colRange = col;
		x.dCols = dCols;
		x.d = d;
		x.rows = x.rowRange.length();
		x.cols = x.colRange.length();
		return x;
	}
	
	/**
	 * 鐠佸墽鐤�i>閸氭垿鍣?i>閸︺劋绗呴弽鍣勬径鍕畱閸婄》绱欑悰灞芥倻闁插繑鍨ㄩ崚妤�?闁插?
	 * @param i 娑撳鐖ｉ妴?	 * @param value 闂�顩︾拋鍓х枂閻ㄥ嫬?閵�	 * 
	 * @see #set(int, int, double)
	 * @see #set(Range, Range, Matrix)
	 */
	public void set(int i, double value){
		if (rows != 1 && cols != 1)
			throw new UnsupportedOperationException("Matrix set, only vector takes one parameter.");
		if (rows == 1)
			set(0, i, value);
		else
			set(i, 0, value);
	}
	
	/**
	 * 鐠佸墽鐤嗛惌鈺呮█閸︺劏顢戞稉?垼i娴犮儱寮烽崚妞剧瑓閺嶅檯閸戣櫣娈戦崐绗�
	 * @param i 鐞涘奔绗呴弽鍥�
	 * @param j 閸掓ぞ绗呴弽鍥�
	 * @param value 闂�顩︾拋鍓х枂閻ㄥ嫬?閵�	 * 
	 * @see #set(int, double)
	 * @see #set(Range, Range, Matrix)
	 */
	public void set(int i, int j, double value){
		if (i < 0 || i >= rows || j < 0 || j >= cols)
			throw new IndexOutOfBoundsException("Matrix set, index out of range."+" i:"+i+"    j:"+j);
		d[(i + rowRange.begin()) * dCols + j + colRange.begin()] = value;
	}
	
	/**
	 * 鐠佸墽鐤嗛張澶庮攽閼煎啫娲块崪灞藉灙閼煎啫娲块崘鍐茬暰閻ㄥ嫬鐡欓惌鈺呮█閻ㄥ?閵�	 * <b><i>NOICE:</i><b>閸欘亝妲哥亸鍡楋紣閺勫海娈戦惌鈺呮█閸婂吋?圭拹婵嗗煂鐎涙劗鐓╅梼鐐?	 * @param row 鐞涘矁?栭崶娣�
	 * @param col 閸掓?栭崶娣�
	 * @param value 闂�顩︾拋鍓х枂閻ㄥ嫮鐓╅梼鐢垫畱閸婄?
	 * 
	 * @see #set(int, double)
	 * @see #set(int, int, double)
	 */
	public void set(Range row, Range col, Matrix value){
		Matrix x = at(row, col);
		if (value.rows != x.rows || value.cols != x.cols)
			throw new IllegalArgumentException("Matrix set, size not match.");
		for (int i = 0; i < x.rows; i++)
			for (int j = 0; j < x.cols; j++)
				x.set(i, j, value.at(i, j));
	}
	
	/**
	 * 鐠佸墽鐤嗛惌鈺呮█閸︺劏顢慽婢跺嫮娈戦崐绗�
	 * @param i 鐞涘奔绗呴弽鍥�
	 * @param value 鐟曚浇顔曠純顔炬畱閸婄?
	 */
	public void setRow(int i, Matrix value){
		if (value.rows != 1)
			throw new IllegalArgumentException("Matrix setRow, accept row vector only.");
		if (value.cols != cols)
			throw new IllegalArgumentException("Matrix setRow, size not match.");
		for (int j = 0; j < value.cols; j++)
			set(i, j, value.at(0, j));
	}
	
	/**
	 * 鐠佸墽鐤嗛惌鈺呮█閸︺劌鍨猧婢跺嫮娈戦崐绗�
	 * @param i 閸掓ぞ绗呴弽鍥�
	 * @param value 鐟曚浇顔曠純顔炬畱閸婄?
	 */
	public void setCol(int i, Matrix value){
		if (value.cols != 1)
			throw new IllegalArgumentException("Matrix setCol, accept column vector only.");
		if (value.rows != rows)
			throw new IllegalArgumentException("Matrix setCol, size not match.");
		for (int j = 0; j < value.rows; j++)
			set(j, i, value.at(j, 0));
	}
	
	/**
	 * 鏉烆剛鐤嗚ぐ鎾冲閻晠妯�?	 * @return 閻晠妯�惃鍕祮缂冾喓?
	 */
	public Matrix t(){
		Matrix x = new Matrix(cols, rows);
		for (int i = 0; i < rows; i++)
			for (int j = 0; j <cols; j++)
				x.set(j, i, at(i, j));
		return x;
	}
	
	/**
	 * 閻晠妯�崝鐘崇?(z = x + y)
	 * <br><b><i>NOTICE:</i></b> 鏉╂瑤閲滈弬瑙勭《鐏忓棛鏁ら惄绋垮閸氬海娈戠紒鎾寸亯閺囨寧宕查崢鐔奉潗閻晠妯�妴?	 * @param x 
	 * @return 缂佹挻鐏夐妴?	 * 
	 * @see #add(Number)
	 * @see #add(Matrix, boolean)
	 * @see #add(Number, boolean)
	 * @see #add(int, int, Number)
	 */
	public Matrix add(Matrix x){
		return add(x,false);
	}
	
	/**
	 * 閻晠妯�崝鐘崇?(z = x + y)
	 * @param x 
	 * @param reserve 閹稿洨銇氶弰顖氭儊娣囨繄鏆�崢鐔奉潗閻晠妯�妴鍌氼洤閺�code>reserve==true</code>閿涘本鏌熷▔鏇炴?	 * @see #add(Matrix)
	 * 閸氾箑鍨敍?柤鎼村繐鐨㈡穱婵堟殌閸樼喎顫愰惌鈺呮█閵? * @return 缂佹挻鐏? * 
	 * @see #add(Matrix)
	 * @see #add(Number)
	 * @see #add(Number, boolean)
	 * @see #add(int, int, Number)
	 */
	public Matrix add(Matrix x, boolean reserve){
		if (rows != x.rows || cols != x.cols)
			throw new IllegalArgumentException("Matrix add, size not match.");
		Matrix y = reserve ? new Matrix(rows, cols): this;
		for (int i = 0; i < rows; i++)
			for (int j = 0; j < cols; j++)
				y.set(i, j, at(i, j) + x.at(i, j));
		return y;
	}
	
	/**
	 * 閻晠妯�崝鐘崇?(z=x+y, x 娑撶儤鐖ｉ柌?
	 * @param x 
	 * @param reserve 閹稿洨銇氶弰顖氭儊娣囨繄鏆�崢鐔奉潗閻晠妯�妴鍌氼洤閺�code>reserve==true</code>閿涘本鏌熷▔鏇炴?	 * @see #add(Number)
	 * 閸氾箑鍨敍?柤鎼村繐鐨㈡穱婵堟殌閸樼喎顫愰惌鈺呮█閵? * @return 缂佹挻鐏? * 
	 * @see #add(Matrix)
	 * @see #add(Number)
	 * @see #add(Matrix, boolean)
	 * @see #add(int, int, Number)
	 */
	public Matrix add(Number x, boolean reserve){
		Matrix y = reserve ? new Matrix(rows, cols): this;
		for (int i = 0; i < rows; i++)
			for (int j = 0; j < cols; j++)
				y.set(i, j, at(i, j) + x.doubleValue());
		return y;
	}
	
	/**
	 * 閻晠妯�崝鐘崇?(z=x+y, x 娑撶儤鐖ｉ柌?
	 *  <br><b><i>NOTICE:</i></b> 鏉╂瑤閲滈弬瑙勭《鐏忓棛鏁ら惄绋垮閸氬海娈戠紒鎾寸亯閺囨寧宕查崢鐔奉潗閻晠妯�妴?	 * @param x 
	 * @return 缂佹挻鐏夐妴?	 * 
	 * @see #add(Matrix)
	 * @see #add(Matrix, boolean)
	 * @see #add(Number, boolean)
	 * @see #add(int, int, Number)
	 */
	public Matrix add(Number x){
		return add(x,false);
	}
	
	/**
	 * 閸︺劎鐓╅梼浣冾攽i閸掓?跺嫬濮炴稉濠佺娑擃亝鏆熼妴?	 * @param i 鐞涘奔绗呴弽鍥�
	 * @param j 閸掓ぞ绗呴弽鍥�
	 * @param value 闂�顩﹂崝鐘垫畱閺佽?
	 */
	public void add(int i, int j, Number value){
		if (i < 0 || i >= rows || j < 0 || j >= cols)
			throw new IndexOutOfBoundsException("Matrix at, index out of range.");
		d[(i + rowRange.begin()) * dCols + j + colRange.begin()] += value.doubleValue();
	}
	
	/**
	 * 閸︺劎鐓╅梼浣冾攽i閸掓?跺嫬鍣洪崢璁崇娑擃亝鏆熼妴?	 * @param i 鐞涘奔绗呴弽鍥�
	 * @param j 閸掓ぞ绗呴弽鍥�
	 * @param value 闂�顩﹂崙蹇曟畱閺佽?
	 */
	public void subtract(int i, int j, Number value){
		if (i < 0 || i >= rows || j < 0 || j >= cols)
			throw new IndexOutOfBoundsException("Matrix at, index out of range.");
		d[(i + rowRange.begin()) * dCols + j + colRange.begin()] -= value.doubleValue();
	}
	
	/**
	 * 閻晠妯�崙蹇旂?(z=x-y)
	 * <br><b><i>NOTICE:</i></b> 閺傝纭剁亸鍡欐暏缂佹挻鐏夐弴鎸庡床閸樼喎顫愰惌鈺呮█閵嗗?顩ч弸婊勫厒娣囨繄鏆�崢鐔奉潗閻晠妯�敍灞煎▏閻€劌顩ф稉瀣╁敩閻緤绱�	 * <pre><code>
	 * Matrix z=x.subtract(y);
	 * </code>
	 * </pre>
	 * @param x 
	 * @return 缂佹挻鐏? * 
	 * @see #subtract(Number)
	 * @see #subtract(Matrix, boolean)
	 * @see #subtract(int, int, Number)
	 * @see #subtract(Number, boolean)
	 */
	public Matrix subtract(Matrix x){
		return subtract(x,false);
	}
	
	/**
	 * 閻晠妯�崙蹇旂?(z=x-y)
	 * @param x 
	 * @param reserve 閹稿洨銇氶弰顖氭儊娣囨繄鏆�崢鐔奉潗閻晠妯�妴鍌氼洤閺嬫粌寮?<code>reserve==true</code>閿涘本鏌熷▔鏇炵殺娣囨繄鏆�崢鐔奉潗閻晠妯�敍灞?嫙鏉╂柨娲栫拋锛勭暬
	 * 缂佹挻鐏夐妴鍌氭儊閸掓瑱绱濋弬瑙勭?閸�	 * @see #subtract(Matrix)
	 * @return 缂佹挻鐏? * 
	 * @see #subtract(Number)
	 * @see #subtract(Matrix)
	 * @see #subtract(int, int, Number)
	 * @see #subtract(Number, boolean)
	 */
	public Matrix subtract(Matrix x, boolean reserve){
		if (x.rows != rows || x.cols != cols)
			throw new IllegalArgumentException("Matrix subtract, size not match.");
		Matrix y = reserve ? new Matrix(rows, cols): this;
		for (int i = 0; i < rows; i++)
			for (int j = 0; j < cols; j++)
				y.set(i, j, at(i, j) - x.at(i, j));
		return y;
	}
	
	/**
	 * 閻晠妯�崙蹇旂?(z=x-y, y 娑撶儤鐖ｉ柌?
	 * <br><b><i>NOTICE:</i></b> 閺傝纭剁亸鍡欐暏缂佹挻鐏夐弴鎸庡床閸樼喎顫愰惌鈺呮█閵嗗?顩ч弸婊勫厒娣囨繄鏆�崢鐔奉潗閻晠妯�敍灞煎▏閻€劌顩ф稉瀣╁敩閻緤绱�	 * <pre><code>
	 * Matrix z=x.subtract(y);
	 * </code>
	 * </pre>
	 * @param x 
	 * @return 缂佹挻鐏? * 
	 * @see #subtract(Matrix)
	 * @see #subtract(Matrix, boolean)
	 * @see #subtract(int, int, Number)
	 * @see #subtract(Number, boolean)
	 */
	public Matrix subtract(Number x){
		return subtract(x, false);
	}
	
	/**
	 * 閻晠妯�崙蹇旂?(z=x-y, x is a scale)
	 * @param x
	 * @param reserve 閹稿洨銇氶弰顖氭儊娣囨繄鏆�崢鐔奉潗閻晠妯�敍?婵?倹鐏夐崣鍌涙?<code>reserve==true</code>閿涘本鏌熷▔鏇炵殺娣囨繄鏆�崢鐔奉潗閻晠妯�妴?	 * 閸氾箑鍨敍灞炬煙濞夋洖鎮�
	 * @see #subtract(Number)
	 * @return 缂佹挻鐏? * @see #subtract(Matrix)
	 * @see #subtract(Matrix, boolean)
	 * @see #subtract(int, int, Number)
	 * @see #subtract(Number)
	 */
	public Matrix subtract(Number x, boolean reserve){
		Matrix y = reserve ? new Matrix(rows, cols): this;
		for (int i = 0; i < rows; i++)
			for (int j = 0; j < cols; j++)
				y.set(i, j, at(i, j) - x.doubleValue());
		return y;
	}
	
	/**
	 * 閻晠妯�稊妯荤?(z=x*y)
	 * @param x
	 * @return 缂佹挻鐏? * @see #multiply(Number)
	 * @see #multiply(Number, boolean)
	 * @see #multiply(int, int, Number)
	 */
	public Matrix multiply(Matrix x){
		if (x.rows != cols)
			throw new IllegalArgumentException("Matrix multiplication, size not match.");
		int m = rows;
		int s = x.rows;
		int n = x.cols;
		Matrix y = new Matrix(m, n);
		for (int i = 0; i < m; i++)
			for (int j = 0; j < n; j++)
				for (int k = 0; k < s; k++)
					y.add(i, j ,at(i, k) * x.at(k, j));
		return y;
	}
	
	/**
	 * 乘，矩阵的乘法
	 * 閻晠妯�弫棰佺?	 * @param x
	 * @param reserve 閹稿洨銇氶弰顖氭儊娣囨繄鏆�崢鐔奉潗閻晠妯�敍?婵?倹鐏夐崣鍌涙?<code>reserve==true</code>閿涘本鏌熷▔鏇炵殺娣囨繄鏆�崢鐔奉潗閻晠妯�妴?	 * 閸氾箑鍨敍灞炬煙濞夋洖鎮�
	 * @see #multiply(Number)
	 * @return 缂佹挻鐏? * @see #multiply(Matrix)
	 * @see #multiply(Number)
	 * @see #multiply(int, int, Number)
	 */
	public Matrix multiply(Number x, boolean reserve){
		Matrix y = reserve ? new Matrix(rows, cols): this;
		for (int i = 0; i < rows; i++)
			for (int j = 0; j < cols; j++)
				y.set(i, j, at(i, j) * x.doubleValue());
		return y;
	}
	
	/**
	 * 閻晠妯�弫棰佺?	 * <br><b><i>NOTICE:</i></b> 閺傝纭剁亸鍡欐暏缂佹挻鐏夐弴鎸庡床閸樼喎顫愰惌鈺呮█閵? * @param x 
	 * @param x
	 * @return 缂佹挻鐏? * @see #multiply(Matrix)
	 * @see #multiply(Number)
	 * @see #multiply(int, int, Number)
	 */
	public Matrix multiply(Number x){
		return multiply(x,false);
	}
	
	/**
	 * 閸︺劏顢慽閸掓婢跺嫪绠绘禒銉ょ娑擃亝鏆熼?	 * @param i 鐞涘奔绗呴弽鍥�
	 * @param j 閸掓ぞ绗呴弽鍥�
	 * @param x
	 * @see #multiply(Matrix)
	 * @see #multiply(Number)
	 * @see #multiply(Number, boolean)
	 */
	public void multiply(int i, int j, Number x){
		if (i < 0 || i >= rows || j < 0 || j >= cols)
			throw new IndexOutOfBoundsException("Matrix at, index out of range.");
		set(i, j, at(i, j) * x.doubleValue());
	}
	
	/**
	 * 閸︺劎鐓╅梼浣冾攽i閸掓?跺嫰娅庨崢璁崇娑擃亝鏆熼妴?	 * @param i 鐞涘奔绗呴弽鍥�
	 * @param j 閸掓ぞ绗呴弽鍥�
	 * @param x 
	 * @see #divide(Number)
	 * @see #divide(Number, boolean)
	 */
	public void divide(int i, int j, Number x){
		if (i < 0 || i >= rows || j < 0 || j >= cols)
			throw new IndexOutOfBoundsException("Matrix at, index out of range.");
		set(i, j, at(i, j)/x.doubleValue());
	}
	
	/**
	 * 閻晠妯�梽銈嗙?(z=x/y, y 娑撶儤鐖ｉ柌?
	 * <br><b><i>NOTICE:</i></b> 閺傝纭剁亸鍡欐暏缂佹挻鐏夐弴鎸庡床閸樼喎顫愰惌鈺呮█閵? * @param x 
	 * @return 缂佹挻鐏夐妴?	 * @see #divide(Number, boolean)
	 * @see #divide(int, int, Number)
	 */
	public Matrix divide(Number x){
		return divide(x,false);
	}
	
	/**
	 * 閻晠妯�梽銈嗙?z=x/y, y 娑撶儤鐖ｉ柌?
	 * @param x 
	 * @param reserve 閹稿洨銇氶弰顖氭儊娣囨繄鏆�崢鐔奉潗閻晠妯�敍灞筋洤閺嬫粌寮?<code>reserve==true</code>閿涘本鏌熷▔鏇炵殺娣囨繄鏆�崢鐔奉潗閻晠妯�敍灞芥儊閸掓瑱绱濋弬瑙勭?閸氬矉绱? * @see #divide(Number)
	 * @return 缂佹挻鐏? */
	public Matrix divide(Number x, boolean reserve){
		if (x.doubleValue() == 0.)
			throw new ArithmeticException("Matrix divide, divisor is 0.");
		Matrix y = reserve? new Matrix(rows, cols): this;
		for (int i = 0; i < rows; i++)
			for (int j = 0; j < cols; j++)
				y.set(i, j, at(i, j)/x.doubleValue());
		return y;
	}
	
	/**
	 * 鐠侊紕鐣婚惌鈺呮█閻ㄥ嫯顢戦崥鎴?闂嗗棗鎮庨惃鍕綆閸婄厧鎮滈柌蹇?	 * @return 閸у洤?閸氭垿鍣洪妴?	 * @see #colMean()
	 */
	public Matrix rowMean(){
		Matrix mean = new Matrix(1, cols);
		for (int i = 0; i < rows; i++)
			mean.add(row(i));
		mean.divide(rows);
		return mean;
	}
	
	/**
	 * 鐠侊紕鐣婚惌鈺呮█閻ㄥ嫬鍨崥鎴?闂嗗棗鎮庨惃鍕綆閸婄厧鎮滈柌蹇?	 * @return 閸у洤?閸氭垿鍣洪妴?	 * @see #rowMean()
	 */
	public Matrix colMean(){
		Matrix mean = new Matrix(rows, 1);
		for (int i = 0; i < cols; i++)
			mean.add(col(i));
		mean.divide(cols);
		return mean;
	}
	
	/**
	 * 鐎靛湱鐓╅梼闈涚磻閺嶅箍?
	 * @param reserve 閹稿洨銇氶弰顖氭儊娣囨繄鏆�崢鐔奉潗閻晠妯�敍灞筋洤閺嬫粌寮?<code>reserve==true</code>閿涘本鏌熷▔鏇炵殺娣囨繄鏆�崢鐔奉潗閻晠妯�敍灞芥儊閸掓瑱绱濋弬瑙勭?閸氬矉绱? * {@link #sqrt()}
	 * @return 缂佹挻鐏夐妴?	 * @see #sqrt()
	 */
	public Matrix sqrt(boolean reserve){
		Matrix x = reserve? new Matrix(rows, cols): this;
		for (int i = 0; i < rows; i++)
			for (int j = 0; j < cols; j++)
				x.set(i, j, Math.sqrt(at(i, j)));
		return x;
	}
	
	/**
	 * 鐎靛湱鐓╅梼闈涚磻閺嶅箍?
	 * <br><b><i>NOTICE:</i></b> 閺傝纭剁亸鍡曞▏閻€劏顓哥粻妤冪波閺嬫粍娴涢幑銏犲斧婵鐓╅梼鐐?	 * @return 缂佹挻鐏夐妴?	 * @see #sqrt(boolean)
	 */
	public Matrix sqrt(){
		return sqrt(false);
	}
	
	/**
	 * 鐠侊紕鐣绘稉銈勯嚋閻晠妯�稊?？閻ㄥ嫬妯婇崚顐�
	 * <p>缂佹瑥鐣炬稉銈勯嚋閻晠妯�閵嗕簜閿涘苯鐣犳禒顑跨闂傚娈戝顔煎焼鐠侊紕鐣绘稉鐚寸窗
	 * <br><i>瀹割喖鍩�code>=sum[abs(x(i,j)-y(i,j)]</code></i></p>
	 * @param x Input matrix x
	 * @return Difference
	 */
	public double difference(Matrix x){
		if (x.rows != rows || x.cols != cols)
			throw new IllegalArgumentException("Matrix difference, size not match.");
		double dif = 0.;
		for (int i = 0; i < rows; i++)
			for (int j = 0; j < cols; j++)
				dif += Math.abs(at(i, j) - x.at(i, j));
		return dif;
	}
	
	/**
	 * 鐠侊紕鐣绘稉銈勯嚋閻晠妯�惃鍒�閼煎啯鏆熼?	 * <p>缂佹瑥鐣炬稉銈勯嚋閻晠妯�閵嗕簜閿涘2閼煎啯鏆熼惃鍕?犳鏌熷▔鏇氳礋閿�	 * <br><i><code>l2-norm=sqrt{sum[x(i, j) - y(i, j)]}</code></i></p>
	 * @param x
	 * @return - l2-norm
	 */
	public double l2Norm(Matrix x){
		double norm = 0.;
		//store the scale, avoid underflow or overflow
		final double TINY = 1e-10;
		for (int i = 0; i < rows; i++)
			for (int j = 0; j < cols; j++){
				double t = at(i, j) - x.at(i, j);
				norm += t*t*TINY;
			}
		norm = Math.sqrt(norm)/TINY;
		return norm;
	}
	
	/**
	 * 閸忓娈曟稉?閲滈惌鈺呮█閵�	 */
	@Override
	public Matrix clone(){
		Matrix x = new Matrix(rows, cols);
		for (int i = 0; i < rows; i++)
			for (int j = 0; j < cols; j++)
				x.set(i, j, at(i, j));
		return x;
	}
	
	/**
	 * 濡�鐓℃稉銈勯嚋閻晠妯�弰顖氭儊閻╁摜鐡戦?	 * @param anotherMat
	 * @return
	 */
	@Override
	public boolean equals(Object obj) {
		Matrix anotherMat = (Matrix)obj;
		if(this.rows() != anotherMat.rows() || this.columns() != anotherMat.columns()) {
			return false;
		}
		
		//Check whether content of the two matrixes are the same
		for(int i=0; i<this.rows(); i++) {
			for(int j=0; j<this.columns(); j++) {
				if(this.at(i, j) != anotherMat.at(i, j)) {
					return false;
				}
			}
		}
		
		return true;
	}
	
	@Override
	public int hashCode() {
		return this.columns() * this.rows();
	}
	
	/**
	 * 鏉堝懎濮弬瑙勭《閿涘苯鐨㈤惌鈺呮█閹垫挸宓冮崚鐗堝付閸掕泛褰�	 */
	public void print(){
		//System.out.println("-------------------------");
		java.text.DecimalFormat f = new java.text.DecimalFormat("#.## ");
		for (int i = 0; i < rows; i++){
			for (int j = 0; j < cols; j++)
				System.out.print(f.format(at(i, j)) + " ");
			System.out.println();
		}
		//System.out.println("-------------------------");
	}
	/***
	 * 娑撳秵鐗稿蹇撳?	 */
	public void printAll(){
		//System.out.println("-------------------------");;
		for (int i = 0; i < rows; i++){
			for (int j = 0; j < cols; j++)
				System.out.print(at(i, j) + " ");
			System.out.println();
		}
		//System.out.println("-------------------------");		
	}
	/**
	 * 閸︺劏顢戦崥搴℃値楠炴湹绔存稉顏嗙叐闂冪?
	 * <p>缂佹瑥鐣炬稉銈勯嚋閻晠妯�閵嗕簜閿?	 * <br>x=
	 * <br>|1 2 3|  
	 * <br>|4 5 6|
	 * <br>|7 8 9| ,
	 * <br>y=
	 * <br>|1 1 2|
	 * <br>|2 2 1|
	 * <br>閸掓瑧绮℃潻鍥ф?楠炶泛鎮楅敍?	 * <br>x=
	 * <br>|1 2 3|  
	 * <br>|4 5 6|
	 * <br>|7 8 9|
	 * <br>|1 1 2|
	 * <br>|2 2 1|
	 * </p>
	 * @param otherMx 
	 */
	public void mergeAfterRow(Matrix otherMx){
		if (otherMx.cols != cols)
			throw new IllegalArgumentException("Matrix merge, size not match.");
		//create a new matrix
		Matrix x = new Matrix(otherMx.rows+this.rows, this.cols);
		//copy this to x
		this.copyTo(x.at(new Range(0, rows), Range.all()));
		//copy otherMx to x
		otherMx.copyTo(x.at(new Range(rows, x.rows), Range.all()));
		this.rows = x.rows;
		this.cols = x.cols;
		this.dCols = x.dCols;
		this.d = x.d;
		this.rowRange = x.rowRange;
		this.colRange = x.colRange;
	}
	/***
	 * 瀵版鍩岄崗鏈佃厬閻ㄥ嫪绔撮?	 * @param colIndex 閸掓娈慽ndex
	 * @return
	 */
	public Matrix getSingerCol(int colIndex){
		Matrix mx=new Matrix(this.rows,1);
		for(int i=0;i<this.rows;i++){
			mx.set(i, 0, this.at(i,colIndex));
		}
		return mx;
	}

	public double[] getall() {
		// TODO Auto-generated method stub
		java.text.DecimalFormat f = new java.text.DecimalFormat("#.## ");
		double[] x = new double[rows];
		for (int i = 0; i < rows; i++){
			for (int j = 0; j < cols; j++){
				//System.out.print(f.format(at(i, j)) + " ");
				x[i] =Double.parseDouble(f.format(at(i, j)));
			}
			//System.out.println();
		}
		return x;
		
	}
}
